package com.liruo.learn.spring.mvc.enumconverter.api;

import com.liruo.learn.spring.mvc.enumconverter.SourceEnum;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author:liruo
 * @Date:2023-02-20-21:29:09
 * @Desc
 */
public class SourceEnumConverterFactory<V> implements EnumConverterFactory<V>{
    private final EnumValueStrategy strategy;

    public SourceEnumConverterFactory() {
        this.strategy = EnumValueStrategy.SOURCE;
    }
    public SourceEnumConverterFactory(EnumValueStrategy strategy) {
        this.strategy = strategy;
    }
    private final Map<Integer, EnumConverter<V, Object>> cache = new ConcurrentHashMap<>();


    public <E> EnumConverter<V, E> getConverter(Class<E> enumClazz){
        if(enumClazz == null){
            throw new NullPointerException("enumeration can't null");
        }
        int hash = enumClazz.getName().hashCode();
        if(cache.containsKey(hash)){
            return (EnumConverter<V, E>)cache.get(hash);
        }

        if(!enumClazz.isEnum()){
            throw new RuntimeException("enumeration can't extends twice other enumeration");
        }
        EnumConverter<V, Object> created;
        switch (this.strategy){
            case NAME-> created = new NameEnumConverter(enumClazz);
            case ORDINAL ->created = new OrdinalEnumConverter(enumClazz);
            case SOURCE -> {
                if(!SourceEnum.class.isAssignableFrom(enumClazz)){
                    throw new RuntimeException("you strategy is " + this.strategy.name()
                            + " , so you must implement " + SourceEnum.class.getName());
                }
                SourceEnum<V> cast = SourceEnum.class.cast(enumClazz.getEnumConstants()[0]);
                V source = cast.getSource();
                if(!(source instanceof Integer) &&  !(source instanceof String)){
                    throw new RuntimeException("");
                }
                created = new SourceEnumConverter(enumClazz);
            }
            default -> throw new RuntimeException("can't create a EnumConverter, may be you strategy"
                    + this.strategy.name() +  " is null");
        }
        cache.put(hash, created);
        return (EnumConverter<V, E>)created;
    }
}
